package cn.crex1.xiaomi.core.orm.datasource;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.crex1.xiaomi.core.orm.datasource.SqlType;
import cn.crex1.xiaomi.core.orm.type.handler.TypeHandler;
import cn.crex1.xiaomi.core.orm.type.handler.TypeHandlerImpl;

/**
 * 
 * sql配置类,预编译sql，设置参数，执行数据库操作
 * @author zzh@crex1
 *
 */
public class Configuration {
	
	//数据源对象，获取数据库连接
	private JdbcDataSource dataSource;

	//sql语句
	private String sql;
	
	//同步锁对象，会降低性能
	private Object queryobj = new Object();
	
	//参数数组
	private List<?> args;
	
	private List<Object> emptyList=new ArrayList<>();
	
	//sql语句执行返回值类型
	private String resultType;

	private String methdResult;
	
	//封装list所需实体类对象
	private Object[] entityobj;
	
	//类型处理器，封装list要用
	private TypeHandler typeHandler;

	private Logger logger = LoggerFactory.getLogger(Configuration.class);

	//实例化所需对象
	public Configuration(Object[] entityobj, JdbcDataSource dataSource, String sql, String resultType, List<?> args, String methdresult) {
		this.entityobj = entityobj;
		this.dataSource = dataSource;
		this.sql = sql;
		this.args = args;
		this.resultType = resultType;
		this.methdResult=methdresult;
		typeHandler=new TypeHandlerImpl();
	}
	
	//获取预编译对象，预编译sql
	private PreparedStatement createPreparedStatement() {
		if (sql.contains("like '%")) {
			sql=sql.replace("?", String.valueOf(args.get(0))).replace("$", String.valueOf(args.get(args.size()-1)));
			try {
				return dataSource.openDataSource().prepareStatement(sql);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		try {
			return dataSource.openDataSource().prepareStatement(sql);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	//反射获取实体类对象的属性数组
	private Field[] getFields() {
		return entityobj[0].getClass().getDeclaredFields();
	}
	
	//获取实体类对象的属性数量
	private int getFieldscount() {
		return getFields().length;
	}
	
	//设置参数，预编译sql
	private PreparedStatement preparedSql() {
		PreparedStatement ps = createPreparedStatement();
		if (sql.contains("like '%")) {
			return ps;
		}
		else if (sql.contains("?") && args.size()>0) {
			for (int i = 0; i < args.size(); i++) {
					try {
						ps.setObject(i + 1, args.get(i));
					} catch (SQLException e) {
						e.printStackTrace();
					}
			}
		}
		return ps;
	}
	
	//获取sql语句的类型
	private SqlType getSqlType() {
		String sqlType = sql.substring(0, sql.indexOf(" "));
		String upperCase = sqlType.toUpperCase();
		if (upperCase.equalsIgnoreCase(SqlType.SELECT.name())) {
			return SqlType.SELECT;
		}
		if (upperCase.equalsIgnoreCase(SqlType.INSERT.name())) {
			return SqlType.INSERT;
		}
		if (upperCase.equalsIgnoreCase(SqlType.DELETE.name())) {
			return SqlType.DELETE;
		}
		if (upperCase.equalsIgnoreCase(SqlType.UPDATE.name())) {
			return SqlType.UPDATE;
		}
		return null;
	}
	
	//获取返回值类型
	private ResultType getResultType() {
		String upperCase = resultType.toUpperCase();
		if (upperCase.equalsIgnoreCase(ResultType.INT.name())) {
			return ResultType.INT;
		}
		if (upperCase.equalsIgnoreCase(ResultType.STRING.name())) {
			return ResultType.STRING;
		}
		if (upperCase.equalsIgnoreCase(ResultType.LIST.name())) {
			return ResultType.LIST;
		}
		return null;
	}
	
	//获取ResultSet存储的记录数
	private int getResultSetCount(ResultSet rs) {
		int count = 0;
		try {
			rs.last();
			count = rs.getRow();
			rs.beforeFirst();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return count;

	}

	//执行数据库操作
	public Object excute() {
		synchronized (queryobj) {
			Object result = null;
			switch (getSqlType()) {
			//执行查询
			case SELECT: result = readExcute(result);
				break;
				////执行插入
			case INSERT: result = wirteExcute(result);
				break;
				//执行删除
			case DELETE: result = wirteExcute(result);
				break;
			//执行更新
			case UPDATE: result = wirteExcute(result);
				break;
			default:
				logger.error("sql error");
				break;
			}
			return result;
		}
	}

	private Object wirteExcute(Object result) {
		   PreparedStatement ps=null;
			try {
				ps=preparedSql();
				result = ps.executeUpdate();
				dataSource.manaedTransaction();
			} catch (SQLException e) {
				e.printStackTrace();
			}finally {
				try {
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		return result;
	}

	private Object readExcute(Object result) {
			ResultSet rs=null;
			PreparedStatement ps=null;
			try {
				ps=preparedSql();
				rs = ps.executeQuery();
				//对事务的管理
				dataSource.manaedTransaction();
				switch (getResultType()) {
				case INT:
					if (getResultSetCount(rs) > 0) {
						while (rs.next()) {
							result = resultWrapperBySelectOneOBj(rs);
							if (result==null) {
								result=0;
							}
						}
					} else {
						result = 0;
					}
					break;
				case STRING:
					if (getResultSetCount(rs) > 0) {
						while (rs.next()) {
							result = resultWrapperBySelectOneOBj(rs);
							if (result==null) {
								result="";
							}
						}
					} else {
						result = "";
					}
					break;
				case LIST:
					result = resultWrapperBySelectlist(rs);
					break;
				default:
					logger.error("result type eroor");
					break;
				}
			} catch (SQLException | InstantiationException | IllegalAccessException e) {
				e.printStackTrace();
			}finally {
				try {
					rs.close();
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		return result;
	}

	private Object resultWrapperBySelectOneOBj(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException {
		if (methdResult.equals(Integer.class.getName())) {
			return rs.getInt(1);
		}
		if (methdResult.equals(Long.class.getName())) {
			return rs.getLong(1);
		}
		if (methdResult.equals(Double.class.getName())) {
			return rs.getDouble(1);
		}
		if (methdResult.equals(Float.class.getName())) {
			return rs.getFloat(1);
		}
		if (methdResult.equals("int")) {
			return rs.getInt(1);
		}
		if (methdResult.equals("long")) {
			return rs.getLong(1);
		}
		if (methdResult.equals("double")) {
			return rs.getDouble(1);
		}
		if (methdResult.equals("float")) {
			return rs.getFloat(1);
		}
		if (methdResult.equals(Date.class.getName())) {
			return rs.getDate(1);
		}
		if (methdResult.equals(String.class.getName())) {
			return rs.getString(1);
		}
		if (methdResult.equals(BigDecimal.class.getName())) {
			return rs.getBigDecimal(1);
		}
		return null;	
	}
	
	private Object resultWrapperBySelectlist(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException {
		Object result;
		List<Object> list = new ArrayList<>();
		Object object = null;
		if (getResultSetCount(rs) > 0) {
			while (rs.next()) {
				object = entityobj[0].getClass().newInstance();
				for (int i = 0; i < getFieldscount(); i++) {
					Field field = getFields()[i];
					field.setAccessible(true);
					try {
						ResultSetMetaData rsmd = rs.getMetaData();
						int columnCount = rsmd.getColumnCount();
						for (int j = 0; j < columnCount; j++) {
							if (rsmd.getColumnName(j+1).equalsIgnoreCase(field.getName())) {
								Object value = rs.getObject(field.getName());
									typeWrapper(object, field, value);																	
							}
						}
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
				list.add(object);
			}
			result = list;
		} else {
			result = emptyList;
		}
		return result;
	}
	private void typeWrapper(Object object, Field field, Object value) throws IllegalAccessException {
			//类型转换
			Object converterTye = typeHandler.converterTye(field.getType().toString(), value);
			//给属性赋值
			field.set(object, converterTye);
	}
}
